#include "IBarrier.h"
#include "cpp_framework.h"

using namespace CMDR;

class TBThreadLocal : public ThreadLocal<int>
{
public:
	int initialValue() { return 0; }
};

class TBThreadLocalID : public ThreadLocal<int>
{
public:
	int initialValue() { return 0; }
};

static int ThreadID = 0;

class TreeBarrier :
	public IBarrier
{
friend class Node;
public: // TreeBarrier Class

	class Node
	{
	friend class TreeBarrier;
	public: // Node Class

		void initNode(int fanout, Node* parent)
		{

			global_sense = 1; // set global to 1 since all threads would get NULL==0 as init.
			_fanout = fanout;
			count.set(_fanout);
			this->parent = parent;
		}
		
		// C'tor to construct root node
		Node(int fanout)
		{
			initNode(fanout,NULL);
		}

		/*
		 * C'tor
		 * parent - the parent node of this new node.
		 */
		Node(int fanout, Node* parent)
		{
			initNode(fanout,parent);
		}
	
		Node() {
			initNode(0, NULL);
		}

		// d'tor
		virtual ~Node(void)
		{
			
		}
	
		void await();

	private: // Node Class
		int _fanout;
		CMDR::AtomicInteger count;
		Node* parent;
		volatile int global_sense; // global barrier sense
	}; // end of inner class Node

	TreeBarrier(int numOfThreads, int fanout)
	{
		_numOfThreads = numOfThreads;
		_radix = fanout;
		_leaf = new Node*[numOfThreads];
		leaves = 0;

		int depth;
		depth = 0;
		int n = _numOfThreads;
		while (n > 1) {
			depth++;
			n = n / _radix;
		}
		Node* root = new Node(_radix);
		build(root, depth - 1);
	}

	virtual ~TreeBarrier(void)
	{
		delete[] _leaf;
		_leaf = NULL;
	}

	/*
	 * inits that _threadID and _threadSense thread specifics.
	 */
	virtual void initThreadLocals(int);

	/* Barrier's await impl */
	virtual void await();

	inline virtual char* getBarrierName()
	{
		return "TreeBarrier";
	}

	void test() {
	}

private: // TreeBarrier Class
	int _radix;    // tree fan-out
	Node** _leaf;  // array of leaf nodes  instead of this - use stl::vector of POINTER to Node. delete in vector invalidates the iterator.
	int leaves;   // used to build tree
	int _numOfThreads;

	TBThreadLocal threadSense; // thread-local sense
	TBThreadLocalID tbThreadId;
	

	// recursive tree constructor
	void build(Node* parent, int depth);

};
